package com.siemens.industrial.web.mvc.service.partner;

import com.siemens.industrial.model.partner.Event;
import com.siemens.industrial.model.partner.Metadata;
import com.siemens.industrial.utils.GlobalResponseCode;
import com.siemens.industrial.utils.JsonToOtherFormat;
import com.siemens.industrial.utils.SiemensException;
import com.siemens.industrial.utils.UUIDGenerator;
import com.siemens.industrial.web.mvc.dao.partner.PartnerEventDao;
import com.siemens.industrial.web.mvc.dao.partner.PartnerMetadataDao;
import com.siemens.industrial.web.mvc.pojo.DataTableQuery;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by qupen on 2016/8/31.
 */
@Service
public class PartnerMetadataService {
    @Resource
    PartnerMetadataDao partnerMetadataDao;

    @Resource
    PartnerEventDao partnerEventDao;

    @Resource
    JdbcTemplate jdbcTemplate;

    @Transactional
    public void batchSave(String tenantId, List<Map<String, Object>> data, String key) {
        Map<String, String> reasons = getAllReason(tenantId, key);
        for (Map<String, Object> meta : data) {

            String reason = meta.get(key + "Reason").toString();
            if (reasons.containsKey(reason)) {
                this.recoverMetadata(tenantId, reasons.get(reason), JsonToOtherFormat.buildJsonToString(meta));
            } else {
                Metadata metadata = new Metadata();
//                metadata.setMetaId(UUIDGenerator.getUUID());
                metadata.setMetaKey(key);
                metadata.setMetaDefinition(JsonToOtherFormat.buildJsonToString(meta));
                partnerMetadataDao.saveMetadata(tenantId, metadata);
            }

            if (key.equals("IDLE") && meta.get("IDLEEvent").equals(true)) {
                createEvent(meta, tenantId);
            }
        }
    }

    public void batchSaveMT(String tenantId, List<Map<String, Object>> data, String key) {
        for (Map<String, Object> meta : data) {
            Metadata metadata = new Metadata();
//            metadata.setMetaId(UUIDGenerator.getUUID());
            metadata.setMetaKey(key);
            metadata.setMetaDefinition(JsonToOtherFormat.buildJsonToString(meta));
            partnerMetadataDao.saveMetadata(tenantId, metadata);
        }
    }

    public Metadata getMetadata(String tenantId, String metaId) {
        return partnerMetadataDao.getMetadata(tenantId, metaId);
    }

    public List<Metadata> getMetadataList(String tenantId) {
        return partnerMetadataDao.getMetadataList(tenantId);
    }

    @Transactional
    public void deleteMetadata(String tenantId, String metaId) throws SiemensException {
        if (partnerMetadataDao.getMetadata(tenantId, metaId) != null) {
            partnerMetadataDao.deleteMetadata(tenantId, metaId);
        } else {
            throw new SiemensException(GlobalResponseCode.ERROR_METADATA_NOT_EXISTED);
        }
    }

    public List<Metadata> getAllByKey(String tenantId, String key) {
        return partnerMetadataDao.findAllByMetaKey(tenantId, key);
    }

    public List<String> getMetaType(String tenantId) {
        List<Metadata> metadataList = this.getAllByKey(tenantId, "MachineNumber");
        List<String> types = new ArrayList<>();
        for (Metadata metadata : metadataList) {
            String definition = metadata.getMetaDefinition();
            Map<String, Object> map = JsonToOtherFormat.buildJsonToMap(definition);
            if (!types.contains(map.get("MachineType").toString())) {
                types.add(map.get("MachineType").toString());
            }
        }
        return types;
    }

    public List<String> getMetaModel(String tenantId, String type) {
        List<Metadata> metadataList = this.getAllByKey(tenantId, "MachineNumber");
        List<String> models = new ArrayList<>();
        for (Metadata metadata : metadataList) {
            String definition = metadata.getMetaDefinition();
            Map<String, Object> map = JsonToOtherFormat.buildJsonToMap(definition);
            if (map.get("MachineType").toString().equals(type)) {
                if (!models.contains(map.get("MachineNumber").toString())) {
                    models.add(map.get("MachineNumber").toString());
                }
            }
        }
        return models;
    }

    public Map<String, Object> getSetting(String tenantId) {
        return partnerMetadataDao.getAvailabilitySetting(tenantId);
    }

    @Transactional
    public void setAvailability(String tenantId, String value) {
        Metadata metadata = partnerMetadataDao.getMetadataByKey(tenantId, "availability");
        if (!metadata.getMetaDefinition().equals(value)) {
            partnerMetadataDao.update(tenantId, value);
        }
    }

    public List<Metadata> getAllBykey(String tenantId, String key) {
        return partnerMetadataDao.findAllByKey(tenantId, key);
    }

    public void recoverMetadata(String tenantId, String metadataId, String definition) {
        partnerMetadataDao.recover(tenantId, metadataId, definition);
    }

    private Map<String, String> getAllReason(String tenantId, String key) {
        List<Metadata> metadataList = this.getAllBykey(tenantId, key);
        Map<String, String> reasons = new HashMap<>();
        for (Metadata meta : metadataList) {
            Map<String, Object> metaDefinition = JsonToOtherFormat.buildJsonToMap(meta.getMetaDefinition());
            Object reason = metaDefinition.get(key + "Reason");
            if (reason != null && !reason.equals("")) {
                reasons.put(reason.toString(), meta.getMetaId());
            }
        }
        return reasons;
    }

//    public void saveStateSettings(List<Map<String, Object>> datas, String tenantId) {
//        SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd");
//        try {
//            Map<String, Object> todaySettings = getSettingsByNow(tenantId);
//            if (todaySettings != null && todaySettings.get("start_time") != null) {
//                //update values
//                String st = String.valueOf(todaySettings.get("start_time"));
//                String et = String.valueOf(todaySettings.get("end_time"));
//                Date startTime = sim.parse(st);
//                Date endTime;
//                if (et.equals("null")) {
//                    endTime = null;
//                } else {
//                    endTime = sim.parse(et);
//                }
//                String value = JsonToOtherFormat.buildJsonToString(datas);
//                partnerMetadataDao.setSttings(tenantId, startTime, endTime, value);
//            } else {
//                Map<String, Object> lastSettings = getLastSettings(tenantId);
//                if (lastSettings != null && lastSettings.get("start_time") != null) {
//                    //update last end time
//                    String st = String.valueOf(lastSettings.get("start_time"));
//                    Date startTime = sim.parse(st);
//                    Date endTime = new Date(sim.parse(sim.format(new Date())).getTime() - 24 * 3600 * 1000);
//                    String value = lastSettings.get("value").toString();
//                    partnerMetadataDao.setSttings(tenantId, startTime, endTime, value);
//                }
//                String value = JsonToOtherFormat.buildJsonToString(datas);
//                partnerMetadataDao.saveSttings(tenantId, value);
//            }
//        } catch (ParseException e) {
//            e.printStackTrace();
//        }
//    }

    public void saveStateSettings(Map<String, Object> data, String tenantId) {
        String mtType = data.get("mtType").toString();
        Map<String, Object> mtValue = ((List<Map<String, Object>>) data.get("mtValue")).get(0);
        Map<String, Object> map = partnerMetadataDao.getOneByType(tenantId, mtType);
        if (map != null) {
            List<Map<String, Object>> a = JsonToOtherFormat.buildJsonToMaps(map.get("value").toString());
            for (Map<String, Object> dbMap : a) {
                if (dbMap.get("stType").equals(mtValue.get("stType"))) {
                    a.remove(dbMap);
                    break;
                }
            }
            a.add(mtValue);
            partnerMetadataDao.updateSettings(tenantId, mtType, JsonToOtherFormat.buildJsonToString(a));
        } else {
            partnerMetadataDao.saveSettings(tenantId, data.get("mtType").toString(), JsonToOtherFormat.buildJsonToString(data.get("mtValue")));
        }
    }

    private Map<String, Object> getLastSettings(String database) {
        return partnerMetadataDao.findLastSetting(database);
    }

    private Map<String, Object> getSettingsByNow(String database) {
        return partnerMetadataDao.findSettingsByNow(database);
    }

    public List<Map<String, Object>> getAllSettings(String database) {
        return partnerMetadataDao.getAllStateSettings(database);
    }

    @Transactional
    public void saveStatusTypes(String database, String data) {
        partnerMetadataDao.deleteStatusType(database);
        partnerMetadataDao.saveStatusType(database, data);
    }

    public Metadata getStatus(String tenantId, String key) {
        return partnerMetadataDao.getMetadataByKey(tenantId, key);
    }

    public void updateById(String tenantId, Object definition, String metaId) {
        Map<String, Object> map = (Map<String, Object>) (definition);
        if (map.containsKey("IDLEEvent")) {
            if (map.get("IDLEEvent").equals(true)) {
                createEvent(map, tenantId);
            }
        }
        partnerMetadataDao.updateById(tenantId, JsonToOtherFormat.buildJsonToString(definition), metaId);
    }

    private void createEvent(Map<String, Object> map, String tenantId) {
        Event event = new Event();
        event.setEventId(UUIDGenerator.getUUID());
        event.setEventType("idle");
        event.setEventName(String.valueOf(map.get("IDLEReason")));
        event.setEventDesc(String.valueOf(map.get("IDLEDescription")));
        partnerEventDao.saveEvent(tenantId, event);
    }

    public Map<String, Object> getAllSettingsByDataTable(String database, HttpServletRequest request) {
        DataTableQuery dt = new DataTableQuery(request);
        List<Map<String, Object>> list = new ArrayList<>();

        String sql = "SELECT * FROM `" + database + "`.state_info where 1=1 ";

        int total = jdbcTemplate.queryForList(sql).size();
        int filteredCount = total;
        if (!dt.getSearch().equals("")) {
            String search = " and (`start_time` like binary '%" + dt.getSearch() + "%' or `value` like binary '%" + dt.getSearch() + "%')";
            sql += search;
            filteredCount = jdbcTemplate.queryForList(sql).size();
        }

        if (!dt.getOrderDBColumn().equals("") && !dt.getOrderAscOrDesc().equals("")) {
            String order = " ORDER BY `" + dt.getOrderDBColumn() + "` " + dt.getOrderAscOrDesc();
            sql += order;
        }

        String limit = " limit " + dt.getStart() + "," + dt.getLength();
        sql += limit;
        list = jdbcTemplate.queryForList(sql);
        return dt.buildResponse(filteredCount, total, list);
    }

    public Map<String, Object> getValueByStType(String tenantId, String type, String stType) {
        Map<String, Object> map = partnerMetadataDao.getOneByType(tenantId, type);
        if(map!=null){
            List<Map<String,Object>> list = JsonToOtherFormat.buildJsonToMaps(map.get("value").toString());
            for(Map<String,Object> a:list){
                if (a.get("stType").equals(stType)){
                    return a;
                }
            }
        }
        return null;
    }

    //get value(status type) by deviceType
    public List<Map<String,Object>> getValueByDeviceType(String tenantId,String type){
        Map<String, Object> map = partnerMetadataDao.getOneByType(tenantId, type);
        if(map!=null){
            List<Map<String,Object>> list = JsonToOtherFormat.buildJsonToMaps(map.get("value").toString());
            return list;
        }
        return null;
    }
}
